
/*
  Copyright 2008-20011 Martin Koerner
  code [at] koerner-de.net
  http://code.google.com/p/printstring/



  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.






  PrintString: for string handling and manipulating

  PrintStringOF: PrintString + write into files or on stdout/stderr
  PrintStringIF: PrintString + read out files or stdin
  PrintStringFile: combines both PrintStringOF and PrintStringIF

  for automatic scanning of numbers in ascii files see PrintStringFile or PrintStringIF
*/

#ifndef PrintString_cpp_09238459z58294018i4
#define PrintString_cpp_09238459z58294018i4

#include "PrintString.hpp"

PrintString::PrintString(void) {Internal_Init(1024);}
PrintString::PrintString(const long anz) {if (anz>0) Internal_Init(anz); else Internal_Init(1024);}
PrintString::PrintString(const char* str) {Internal_Init(1024); *this << (char*) str;}
PrintString::PrintString(const PrintString &str) {Internal_Init(1024); Internal_Append( str.c_str(), str.Len());}
PrintString::PrintString(const std::string &str) {Internal_Init(1024); Internal_Append( (char*) str.c_str(), str.length());}


PrintString operator+ (const PrintString &str1, const PrintString &str2)
{
  PrintString ret = str1;
  ret += str2;
  return ret;
}

PrintString operator+ (const PrintString &str1, const char *str2)
{
  PrintString ret = str1;
  ret += str2;
  return ret;
}
PrintString operator+ (const char* str1, const PrintString &str2)
{
  PrintString ret = str1;
  ret += str2;
  return ret;
}

PrintString operator+ (const PrintString &str1, const std::string &str2)
{
  PrintString ret = str1;
  ret += str2;
  return ret;
}

PrintString operator+ (const std::string &str1, const PrintString &str2)
{
  PrintString ret = str1;
  ret += str2;
  return ret;
}




PrintString operator- (const PrintString &str1, const PrintString &str2)
{
  PrintString ret = str1;
  ret.Remove(str2);
  return ret;
}

PrintString operator- (const PrintString &str1, const char *str2)
{
  PrintString ret = str1;
  ret.Remove(str2);
  return ret;
}

PrintString operator- (const char* str1, const PrintString &str2)
{
  PrintString ret = str1;
  ret.Remove(str2);
  return ret;
}

PrintString operator- (const PrintString &str1, const std::string &str2)
{
  PrintString ret = str1;
  ret.Remove(str2);
  return ret;
}

PrintString operator- (const std::string &str1, const PrintString &str2)
{
  PrintString ret = str1;
  ret.Remove(str2);
  return ret;
}


char PrintString::Resize(const long anz_t, const bool round_up)
{
  char *temp_str;
  long anz = anz_t;
  if (round_up) anz = ((anz/1024)+2)*1024;
  
  try {temp_str = new char [anz];}
  catch (std::exception& /*e*/) {return 1;}
  
  if ( Str!=(char*)0 )
  {
    long len = Pos;
    if (len>anz) len=anz;
    Internal_Copy( temp_str, Str, len);
  
    delete [] Str;
  }
  if (Anz>anz) Internal_ResetLines();
  
  Str = temp_str;
  Anz = anz;
  if (Pos>=Anz) Pos=Anz-1;
  Str[Anz-1]=0;
  
  return 0;
}



char* PrintString::GetCopyString(void) const
{
  if (Str==(char*)0) return (char*)0;
  char* temp;
  try {temp = new char [Pos+1];}
  catch (std::exception& /*e*/) {return (char*)0;}
  Internal_Copy( temp, Str, Pos+1);
  return temp;
}





char PrintString::Printf(const char *str, ...)
{
  va_list arg;
  va_start(arg, str);
  char ret = Internal_Printf( str, arg);
  va_end(arg);
  return ret;
}

char PrintString::PPrintf(const char *str, ...)
{
  long old_pos = Pos;
  va_list arg;
  va_start(arg, str);
  char ret = Internal_Printf( str, arg);
  va_end(arg);

  if (ret == 0)
  {
    long len = Pos - old_pos;
    char *temp;
    try {temp = new char [len];}
    catch (std::exception& /*e*/) {Pos = old_pos; Str[Pos] = 0; return 1;}

    if ((ret = Internal_Copy( temp, &Str[old_pos], len))) return ret;
    Pos = old_pos;
    Str[Pos] = 0;
    if ((ret = Internal_Shift( 0, len))) return ret;
    if ((ret = Internal_Copy( Str, temp, len))) return ret;

    delete [] temp;
  }

  return ret;
}

char PrintString::EPrintf(const char *str, ...)
{
  Empty();
  va_list arg;
  va_start(arg, str);
  char ret = Internal_Printf( str, arg);
  va_end(arg);
  return ret;
}

long PrintString::Scanf(const char *str, ...) const
{
  if (Str==(char*)0) return -1;
  va_list arg;
  va_start(arg, str);
  long ret = vsscanf( Str, str, arg);
  va_end(arg);
  return ret;
}








bool PrintString::Compare(const char *str, const long modus) const
{
  if (str==(char*)0) return false;
  if (!modus)
  {
    for (long i=0; i<=Pos; i++)
    {
      if (str[i]!=Str[i]) return false;
    }
  }
  else
  {
    return false;
    // #### NOT TESTED YEYT ####
    /*
    char mask[256][5]; // need to be initialied befor using
    long i=0, j=0, len=0;
    long index;
    bool identical=false;
    unsigned char *str1 = (unsigned char*) Str;
    unsigned char *str2 = (unsigned char*) str;
    
    while (str[len]) len++;
    
    while (i<Pos && j<len)
    {
      if (!mask[str1[i]][0]) i++;
      else if (!mask[str2[j]][0]) j++;
      else
      {
        index=0;
        identical=false;
        while (!identical && index<5 && mask[str1[i]][index])
        {
          if (mask[str1[i]][index]==str2[j]) identical = true;
          else index++;
        }
        if (!identical) return false;
        i++;
        j++;
      }
    }
    if (i!=Pos || j!=len) return false;
    */
  }
  return true;
}

char PrintString::PutChar(const char val, const long num, const long index_t, const long from)
{
  if (Str==(char*)0) return -1;
  long index = index_t;
  if (val==0) return 0;
  if (index<0||index>Pos) return -1;
  if (num<=0) return 0;
  
  if (from==End) index=Pos-index;
  
  if (char ret = Internal_Shift( index, num)) return ret;
  for (long p=0; p<num; p++) Str[p+index]=val;
  Internal_ResetLines();
  return 0;
}

char PrintString::Remove( const char val)
{
  if (Str==(char*)0) return -1;
  long new_pos=0;
  for (long i=0;i<Pos;i++)
  {
    if (Str[i]!=val) Str[new_pos++]=Str[i];
  }
  if (new_pos!=Pos)
  {
    Pos=new_pos;
    Str[Pos]=0;
    Internal_ResetLines();
  }
  return 0;
}

char PrintString::Remove( const char *val)
{
  if (Str==(char*)0) return -1;
  if (val==(char*)0) return 0;
  long length=0, j;
  while (val[length]) length++;
  
  if (length==0) return 0;
  for (long i=0;i<Pos;i++)
  {
    j=0;
    while (j<length && i+j<Pos && Str[i+j]==val[j]) j++;
    if (j==length)
    {
      Internal_Shift( i+length, -length);
    }
  }
  return 0;
}

char PrintString::Replace( const char *val1, const char *val2)
{
  if (Str==(char*)0) return -1;
  if (val1==(char*)0 || val2==(char*)0) return 0;
  long length1=0, length2=0, j, shift;
  while (val1[length1]) length1++;
  while (val2[length2]) length2++;
  
  if (length1==0) return 0;
  else if (length1==1 && length2==1) return Replace( val1[0], val2[0]);
  else if (length1==1 && length2==0) return Remove( val1[0]);
  else if (length2==0) return Remove( val1);
  
  shift = length2-length1;
  
  for (long i=0; i<Pos; i++)
  {
    j=0;
    while (j<length1 && i+j<Pos && Str[i+j]==val1[j]) j++;
    if (j==length1)
    {
      if (char ret = Internal_Shift( i+length1, shift)) return ret;
      Internal_Copy( &Str[i], val2, length2);
      i+=length2;
    }
  }
  return 0;
}

long PrintString::Find( const char val, const long num, const long from, const long offset) const
{
  if (Str==(char*)0) return -1;
  if (num<=0) return -1;
  
  long counter=0;
  if (from == First)
  {
    for (long i=( offset>=0 ? offset : 0); i<Pos; i++)
    {
      if (Str[i]==val)  if ( ++counter == num ) return i;
    }
  }
  else if (from == Last)
  {
    for (long i=Pos-(offset>=0 ? offset : - offset)-1; i>=0; i--)
    {
      if (Str[i]==val)  if ( ++counter == num ) return i;
    }
  }
  
  return -1;
}

long PrintString::Find( const char* str, const long num, const long from, const long offset) const
{
  if (Str==(char*)0) return -1;
  if (str==(char*)0) return -1;
  if (num<=0) return -1;

  long length=0, counter=0;
  while (str[length]) length++;
  if (length==0) return -3;
  
  if (from == First)
  {
    for (long i=(offset>=0 ? offset : 0); i<=Pos-length; i++)
    {
      long j=0;
      while (j<length && i+j<Pos && Str[i+j]==str[j]) j++;
      if (j==length)
      {
        counter++;
        if ( counter == num ) return i;
      }
    }
  }
  else if (from == Last)
  {
    for (long i=Pos-length-(offset>=0 ? offset : - offset)-1; i>=0; i--)
    {
      long j=0;
      while (j<length && i+j<Pos && Str[i+j]==str[j]) j++;
      if (j==length)
      {
        if ( ++counter == num ) return i;
      }
    }
  }

  return -1;
}

long PrintString::Count( const char val, const long from, const long offset) const
{
  if (Str==(char*)0) return -1;
  long counter=0;
  if (from == First)
  {
    for (long i=( offset>=0 ? offset : 0); i<Pos; i++)
    {
      if (Str[i]==val) counter++;
    }
  }
  else if (from == Last)
  {
    for (long i=Pos-(offset>=0 ? offset : - offset)-1; i>=0; i--)
    {
      if (Str[i]==val)  counter++;
    }
  }
  else return -1;
  
  return counter;
}

long PrintString::Count( const char* str, const long from, const long offset) const
{
  if (Str==(char*)0) return -1;
  if (str==(char*)0) return -1;

  long length=0, counter=0;
  while (str[length]) length++;
  if (length==0) return -3;
  
  if (from == First)
  {
    for (long i=(offset>=0 ? offset : 0); i<=Pos-length; i++)
    {
      long j=0;
      while (j<length && i+j<Pos && Str[i+j]==str[j]) j++;
      if (j==length) counter++;
    }
  }
  else if (from == Last)
  {
    for (long i=Pos-length-(offset>=0 ? offset : - offset); i>=0; i--)
    {
      long j=0;
      while (j<length && i+j<Pos && Str[i+j]==str[j]) j++;
      if (j==length) counter++;
    }
  }
  else return -1;
  
  return counter;
}

char PrintString::Truncate( const long pos, const long what)
{
  if (Str==(char*)0) return -1;
  if (pos>=Pos||pos<0) return -1;
  if (what==Last)
  {
    Str[pos] = 0;
    Pos = pos;
    return 0;
  }
  else if (what==First)
  {
    if (char ret = Internal_Shift( pos, -pos)) return ret;
    return 0;
  }
  else return -1;
}










long PrintString::GetNumberOfLines(void)
{
  if (Str==(char*)0) return -1;
  if (Pos==0) return 0;
  if (LineNum>0) return LineNum;
  long num = 0;
  if (LinePos>0 && LineIndex>0)
  {
    num = Count( '\n', First, LinePos) + LineIndex;
  }
  else num = Count( '\n');

  if (Str[Pos-1]=='\n') return LineNum = num;
  else return LineNum = num+1;
}

long PrintString::GetNumberOfLinesConst(void) const
{
  if (Str==(char*)0) return -1;
  if (Pos==0) return 0;

  long num = Count( '\n');
  if (Str[Pos-1]=='\n') return num;
  else return num+1;
}



long PrintString::Line2Index( const long line) const
{
  if (Str==(char*)0) return -1;
  if (line==0) return 0;
  if (line>0)
  {
    if (LineNum>0 && line>=LineNum) return -2;
    if (line==LineIndex) return LinePos;
    else if (LineIndex<line)
    {
      if (LineNum==0 || (LineNum-LineIndex)/2>=(LineIndex-line) )
      {
        long pos = Find( '\n', line-LineIndex, First, LinePos);
        if (pos<0 || pos==Pos-1) return -1;
        else return pos + 1;
      }
      else
      {
        long count = LineNum - line;
        if (Str[Pos-1]=='\n') count++;

        long pos = Find( '\n', count, Last);
        if (pos<0 || pos==Pos-1) return -1;
        else return pos + 1;
      }
    }
    else
    {
      if (line<=LineIndex/2)
      {
        long pos = Find( '\n', line, First);
        if (pos<0 || pos==Pos-1) return -1;
        else return pos + 1;
      }
      else
      {
        long pos = Find( '\n', LineIndex-line+1, Last, Pos-LinePos);
        if (pos<0 || pos==Pos-1) return -1;
        else return pos + 1;
      }
    }
  }
  else return -1;
}


long PrintString::Index2Line(const long pos) const
{
  if (Str==(char*)0) return -1;
  if (pos<0 || pos>=Pos) return -1;

  long counter = 0;
  long start = 0;

  if (LinePos<=pos)
  {
    counter = LineIndex;
    start = LinePos;
  }

  for (long i=start; i<pos; i++)
  {
    if(Str[i] == '\n') counter++;
  }
  return counter;
}

char PrintString::GetLineConst(PrintString &str, const long line) const
{
  if (Str==(char*)0) return -1;
  long start = Line2Index(line);
  if (start<0) return 1;
  
  long end = Find( '\n', 1, First, start);
  if (end<0) end = Pos;
  
  str.Empty();

  if (str.Anz<=end-start+1)  str.Resize(end-start+1, true);
  return Internal_Copy( str.Str, &Str[start], end-start);
}

char PrintString::GetLine(PrintString &str, const long line)
{
  if (Str==(char*)0) return -1;
  long start = Line2Index(line);
  if (start<0) return 1;
  
  long end = Find( '\n', 1, First, start);
  if (end<0) end = Pos;

  LineIndex = line;
  LinePos = start;

  str.Empty();
  
  if (str.Anz<=end-start+1)  str.Resize(end-start+1, true);
  return Internal_Copy( str.Str, &Str[start], end-start);
}

char PrintString::RemoveLine( const long line)
{
  if (Str==(char*)0) return -1;
  long start = Line2Index(line);
  if (start<0) return 1;
  
  long end = Find( '\n', 1, First, start);
  if (end<0) end = Pos;
  else
  {
    end++;
    LineIndex = line;
    LinePos = start;
  }
  if (LineNum>0)  LineNum--;
  
  return Internal_Shift( end, start-end);
}

char PrintString::ReplaceLine( const char* str, const long line)
{
  if (Str==(char*)0) return -1;
  if (str==(char*)0) return 1;
  
  long len = 0;
  while (str[len]) len++;
  if (len==0) return 1;
  if (str[len-1]=='\n') len--;
  
  long start = Line2Index(line);;
  if (start<0) return 1;
  
  long end = Find( '\n', 1, First, start);
  if (end<0) end = Pos;
  

  LineIndex = line;
  LinePos = start;
  
  long shift = len - (end-start);
  if ( shift!=0)
  {
    if (char ret = Internal_Shift( end, shift)) return ret;
  }
  return Internal_Copy( &Str[start], str, len);
}


















PrintString& PrintString::Internal_Append(const char *str, const long length)
{
  if (length<=0) return *this;

  if ( Pos+length >= Anz )
  {
    if (Resize( Pos+length+2, true)) return *this;
  }

  Internal_Copy( &Str[Pos], str, length);

  Internal_ResetLines();
  Str[Pos+=length] = 0;
  return *this;
}


char PrintString::Internal_Copy( char* to, const char* from, const long len)
{
#ifdef __INTEL_COMPILER
  for (long i=0; i<len; i++) to[i]=from[i];
#else
  memcpy( (void*) to, (const void*) from, len);
#endif
  return 0;
}

void PrintString::Internal_Init( const long anz)
{
  Pos = 0;
  Anz = anz;
  Internal_ResetLines();
  try {Str = new char [Anz];}
  catch (std::exception& /*e*/) {Str = (char *) 0; Anz=0; return;}
  Str[0]=0;
  return;
}

char PrintString::Internal_Printf(const char *str, va_list arg)
{
  //int vsnprintf( char* buf, size_t count, const char* format, va_list arg );
  va_list cp_arg; //need a copy of arg, because: if vsnprintf fails, and one need more memory, there is no way to rewind the arg list
  va_copy( cp_arg, arg); //copy the arg list
  long new_pos = vsnprintf( &Str[Pos], Anz-Pos, str, cp_arg) + Pos+1;
  va_end(cp_arg); //delete the copy

  if (new_pos>Anz) //there was not enough space in Str to save the string
  {
    if (Resize(new_pos+2, true))
    {
      Str[Pos]=0;
      return 1;
    }
    va_copy( cp_arg, arg); //copy again the arg list
    new_pos = vsnprintf( &Str[Pos], Anz-Pos, str, cp_arg) + Pos+1;
    va_end(cp_arg); //delete again the copy
    if (new_pos>Anz) {Str[Pos]=0; return -1;} //it failed again
  }

  Internal_ResetLines();
  Pos=new_pos-1;
  return 0;
}

char PrintString::Internal_Shift( const long index, const long shift)
{
  if (shift==0) return 0;
  if (index<0||index>Pos) return -1;
  if (Pos+shift>Anz)
  {
    if (char ret = Resize(Pos+shift+1, true)) return ret;
  }

#ifdef __INTEL_COMPILER
  if (shift<0)
  {
    long shift_t = -shift;
    if (index<shift_t) shift_t=index;
    for (long p=index; p<Pos; p++) Str[p-shift_t]=Str[p];
    Pos-=shift_t;
  }
  else if (shift>0)
  {
    for (long p=Pos-1; p>=index; p--) Str[p+shift]=Str[p];
    Pos+=shift;
  }

#else
  long to = index+shift;
  if (to<0) to = 0;
  long len = Pos-index;
  Pos+=shift;
  if (len<0) len=-len;

  memmove( &Str[to], &Str[index], len);
#endif

  Internal_ResetLines();
  Str[Pos]=0;
  return 0;
}

























PrintString& PrintString::operator << (const char *str)
{
  if (str==(char*)0) return *this;
  long l=0; while (str[l]) l++;
  return Internal_Append( str, l);
}

PrintString& PrintString::operator << (const PrintString &str)
{
  return Internal_Append( str.c_str(), str.Len());
}

PrintString& PrintString::operator << (const std::string &str)
{
  return Internal_Append( (char*) str.c_str(), str.length());
}

PrintString& PrintString::operator << (const double val)
{
  std::ostringstream o_stream; //use a ostringstream to convert numbers into a string
  o_stream.flags( std::ios::scientific); //use scientific mod for floats (e.g. 2.30000e-3)
  o_stream << val;
  if (o_stream.fail()) return *this; //if it fails, return the current non modified PrintString object
  else return *this << o_stream.str().c_str(); //else append the char-string of the ostringstream object to the current PrintString object and return
}

PrintString& PrintString::operator << ( const long double val)
{
  std::ostringstream o_stream; //use a ostringstream to convert numbers into a string
  o_stream.flags( std::ios::scientific); //use scientific mod for floats (e.g. 2.30000e-3)
  o_stream << val;
  if (o_stream.fail()) return *this; //if it fails, return the current non modified PrintString object
  else return *this << o_stream.str().c_str(); //else append the char-string of the ostringstream object to the current PrintString object and return
}

PrintString& PrintString::operator << ( const bool val)
{
  if (val) return *this << "true";
  else return *this << "false";
}

PrintString& PrintString::operator << (const long val)
{
  std::ostringstream o_stream;
  o_stream << val;
  if (o_stream.fail()) return *this;
  else return *this << o_stream.str().c_str();
}

PrintString& PrintString::operator << (const unsigned long val)
{
  std::ostringstream o_stream;
  o_stream << val;
  if (o_stream.fail()) return *this;
  else return *this << o_stream.str().c_str();
}
























char PrintStringFileVirtual::ClearFile(const char* str)
{
  if (  str!=(char*)0 && str[0]!=0 && FileExist( str))
  {
    std::fstream datei;
    
    datei.open( str, std::fstream::out | std::fstream::trunc | std::fstream::binary);
    datei.close();
    if (!datei.fail()) return 0;
    
    Error << "Error in ClearFile("<< str << "): Could not clear file.\n";
  }
  else Error << "Error in ClearFile("<< str << "): File does not exist or filename is not set.\n";

  IsFailed = true;
  return 1;
}


char PrintStringFileVirtual::RemoveFile(const char* str)
{
  if ( str!=(char*)0 && str[0]!=0 && FileExist( str))
  {
    if (! remove( str)) return 0;
    else Error << "Error in RemoveFile("<< str << "): Could not delete file filename.\n";
  }
  else Error << "Error in RemoveFile("<< str << "): File does not exist.\n";

  IsFailed = true;
  return 1;
}


char PrintStringFileVirtual::TouchFile(const char* str)
{
  if (  str!=(char*)0 && str[0]!=0)
  {
    int id = open( FileName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
    if (id == -1)
    {
      Error << "Error in TouchFile("<< str << "): Could not touch file.\n";
      return 1;
    }
    close(id);
    return 0;
  }
  else Error << "Error in TouchFile("<< str << "): You musst specify the filename.\n";

  IsFailed = true;
  return 1;
}


bool PrintStringFileVirtual::FileExist(const char* str)
{
  if ( str==(const char*)0 || str[0]==0)
  {
    Error << "Error in TouchFile("<< str << "): Could not touch file.\n";
    IsFailed = true;
    return false;
  }
  
  std::fstream datei;
  datei.open( str, std::fstream::in);
  datei.close();
  if (datei.fail()) return false;
  else return true;
}

char PrintStringFileVirtual::GetLock(void)
{
  if (!LockFile && !TryLockFile) return 0;

  struct flock lock_struct;

  if ( !FileExist())
  {
    if (TouchFile()) return -1;
  }
  

  LockID  = open( FileName.c_str(), O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP);
  if (LockID==-1)
  {
    IsFailed = true;
    Error << "Error GetLock(" << FileName << "): Could not open file.\n";
    return -1;
  }
  
  lock_struct.l_type = F_RDLCK;
  lock_struct.l_whence = SEEK_SET;
  lock_struct.l_start = 1;
  lock_struct.l_len = 1;
  
  if (TryLockFile)
  {
    if (fcntl( LockID, F_SETLK, &lock_struct) == -1)
    {
      IsFailed = true;
      Error << "Error GetLock(" << FileName << "): Did not get the Lock!\n";
      return 1;
    }
  }
  else
  {
    // for me the F_SETLKW mode did not worked on filesystems mounted from a server
    while (fcntl( LockID, F_SETLK, &lock_struct) == -1) usleep(1000000);
  }
  
  return 0;
}

char PrintStringFileVirtual::FreeLock(void)
{
  if (!LockFile && !TryLockFile) return 0;
  if (LockID == 0 || LockID == -1)
  {
    Error << "Error FreeLock(" << FileName << "): There is no lock to free!\n";
    return 1;
  }
  struct flock lock_struct;
  
  lock_struct.l_type = F_UNLCK;
  lock_struct.l_whence = SEEK_SET;
  lock_struct.l_start = 1;
  lock_struct.l_len = 1;
  
  while (fcntl( LockID, F_SETLK, &lock_struct) == -1) usleep(1000000);
  close(LockID);
  LockID=0;
  return 0;
}


void PrintStringFileVirtual::InitAllEmpty(void)
{
  WriteProtection = false;
  IsFailed = false;
  FileName.Empty();
  FILE_Handler = (FILE*)0;
  fstream_Handler = (std::fstream*)0;
  return;
}















char PrintStringIF::ReadIn(void)
{
  WriteProtection = true;
  if ( FileName.Len()>0)
  {
    if (char ret = GetLock()) return ret;
    
    std::fstream datei;
    datei.open( FileName.c_str(), std::fstream::in | std::fstream::binary);
    if (datei.fail())
    {
      IsFailed = true;
      Error << "Error ReadIn(" << FileName << "): Could not open file.\n";
      datei.close();
      return 1;
    }
    char ret = ReadIn( &datei);
    datei.close();
    
    if (FreeLock() || ret)  return 1;

    return 0;
  }
  else if (fstream_Handler != (std::fstream*)0) return ReadIn( fstream_Handler);
  else if (FILE_Handler != (FILE*)0) return ReadIn( FILE_Handler);

  IsFailed = true;
  Error << "Error ReadIn(): You musst specify the filename or a file handler.\n";
  return 1;
}


char PrintStringIF::ReadIn(FILE *datei)
{
  IsFailed = true;
  if (datei == (FILE*)0) {Error << "Error in ReadIn(FILE *datei): File handler is NULL pointer.\n"; return 1;}
  
  if ( ferror( datei) ) {Error << "Error in ReadIn(FILE *datei): Did not read out of file, because the file handler indicates an error.\n"; return 1;}
  
  long old_pos = ftell( datei);
  
  fseek( datei, 0, SEEK_END);
  long length = ftell( datei);
  
  if ( ferror( datei) ) {Error << "Error in ReadIn(FILE *datei): Cannot detect size of file.\n"; return 1;}
  
  if (Pos + length >= Anz)
  {
    if (char ret = Resize(Pos+length+2, true)) return ret;
  }
  fseek( datei, 0, SEEK_SET);
  
  fread( &Str[Pos], 1, length, datei);
  
  fseek( datei, old_pos, SEEK_SET);
  
  if ( ferror( datei) )
  {
    Str[Pos]=0;
    Error << "Error in ReadIn(FILE *datei): Failed to read out of file.\n";
    return 1;
  }
  
  Pos+=length;
  Str[Pos++]=0;
  
  IsFailed = false;
  return 0;
}

char PrintStringIF::ReadIn( std::fstream *datei)
{
  IsFailed = true;
  if (datei == (std::fstream*)0) {Error << "Error in ReadIn( std::fstream *datei): File handler is NULL pointer.\n"; return 1;}
  
  if ( datei->fail() ) {Error << "Error in ReadIn( std::fstream *datei): Did not read out of file, because the file handler indicates an error.\n"; return 1;}
  if (! datei->is_open()) {Error << "Error in ReadIn( std::fstream *datei): File is not opened.\n"; return 1;}
  
  long old_pos = datei->tellg();
  
  datei->seekg( 0, std::ios_base::end);
  long length = datei->tellg();
  
  if (Pos + length >= Anz)
  {
    if (char ret = Resize(Pos+length+2, true)) return ret;
  }
  datei->seekg( 0, std::ios_base::beg);
  
  datei->read( &Str[Pos], length);
  
  datei->seekg( old_pos, std::ios_base::beg);
  
  if ( datei->fail() )
  {
    Str[Pos]=0;
    Error << "Error in ReadIn( std::fstream *datei): Failed to read out of file.\n";
    return 1;
  }
  
  Pos+=length;
  Str[Pos]=0;
  
  IsFailed = false;
  return 0;
}



char PrintStringIF::ExtractData( const bool use_long)
{
  Lines=0; Columns=0;
  
  long temp_columns=0;
  char state = 0;
  for (long i=0; i<Pos; i++)
  {
    switch (state)
    {
      case 0: //beginning of a new line
        if (temp_columns)
        {
          if (Columns==0) Columns=temp_columns;
          else if (Columns!=temp_columns)
          {
            Columns=0; Lines=0;
            IsFailed = true;
            Error << "Error in ExtractData(" << use_long << "): different number of columns detected.\n";
            return 1;
          }
          Lines++;
        }
        temp_columns=0;
        if (Str[i]=='#') state=2;
        else if (Str[i]=='\n') state=0;
        else {state=1;}
        break;
      case 1: //detecting numbers
        if ( (Str[i]==' ' || Str[i]=='\t') && (Str[i-1]!=' ' && Str[i-1]!='\t')) temp_columns++;
        else if (Str[i]=='\n') {state=0; if (Str[i-1]!=' ' && Str[i-1]!='\t') {temp_columns++;}}
        else if (Str[i]=='#') {state=2; if (Str[i-1]!=' ' && Str[i-1]!='\t') {temp_columns++;}}
        break;
      case 2: //comments
        if (Str[i]=='\n') state=0;
        break;
    }
  }
  
  if (state==1 && Str[Pos-1]!=' ') {temp_columns++; state=0;}
  
  if (state==0 && temp_columns)
  {
    if (Columns==0) Columns=temp_columns;
    else if (Columns!=temp_columns)
    {
      Columns=0; Lines=0;
      IsFailed = true;
      Error << "Error in ExtractData(" << use_long << "): different number of columns detected.\n";
      return 1;
    }
    Lines++;
  }

  if (use_long)
  {
    if (DataL != (long*)0) delete [] DataL;
    try {DataL = new long[Columns*Lines];}
    catch (std::exception& e)
    {
      DataL = (long*) 0;
      IsFailed = true;
      Error.Printf("Memory allocation error: could not get %d od typ long: \"%s\"\n", Columns*Lines, e.what());
      return -1;
    }
  }
  else
  {
    if (DataD != (double*)0) delete [] DataD;
    try {DataD = new double[Columns*Lines];}
    catch (std::exception& e)
    {
      DataD = (double*) 0;
      IsFailed = true;
      Error.Printf("Memory allocation error: could not get %d od typ double: \"%s\"\n", Columns*Lines, e.what());
      return -1;
    }
  }
  
  bool comment = false;
  long pos_data=0;
  for (long i=0; i<Pos-1; i++)
  {
    if (Str[i]=='#') comment=true;
    else if (Str[i]=='\n') comment=false;
    else if (!comment)
    {
      while ( i<Pos && (Str[i]==' ' || Str[i]=='\t')) i++;

      if (use_long) DataL[pos_data++]=atol(&Str[i]);
      else DataD[pos_data++]=atof(&Str[i]);

      while ( i<Pos && (Str[i]!=' ' && Str[i]!='\t') && Str[i]!='\n' && Str[i] != '#') i++;
    }
  }
  
  return 0;
}




















char PrintStringOF::FlushOut(void)
{
  if (char ret = WriteOut()) return ret;
  if (DeleteAfterFlush) Empty();
  return 0;
}

char PrintStringOF::FlushStdOut(void)
{
  if (char ret = WriteOut(stdout)) return ret;
  if (DeleteAfterFlush) Empty();
  return 0;
}

char PrintStringOF::FlushStdError(void)
{
  if (char ret = WriteOut(stderr)) return ret;
  if (DeleteAfterFlush) Empty();
  return 0;
}

char PrintStringOF::WriteOut(void)
{
  if (Len()<=0) return 0;
  if (WriteProtection) {Error << "Error in WriteOut(" << FileName << "): WriteProtection is turned on.\n"; return -1;}
  
  if ( FileName.Len()>0)
  {
    if (char ret = GetLock()) return ret;
    
    std::fstream datei;
    datei.open( FileName.c_str(), std::fstream::out | std::fstream::app | std::fstream::binary);
    if (datei.fail())
    {
      IsFailed = true;
      Error << "Error in WriteOut(" << FileName << "): Could not open file.\n";
      datei.close();
      return 1;
    }
    char ret = WriteOut( &datei);
    datei.close();
    
    if (FreeLock() || ret) return 1;

    return 0;
  }
  else if (fstream_Handler != (std::fstream*)0) return WriteOut( fstream_Handler);
  else if (FILE_Handler != (FILE*)0) return WriteOut( FILE_Handler);
  
  IsFailed = true;
  Error << "Error in WriteOut(): You musst specify the filename or a file handler.\n";
  return 1;
}

char PrintStringOF::WriteOut( FILE *datei)
{
  if (Len()<=0) return 0;
  IsFailed = true;

  if (WriteProtection && !(datei==stdout || datei==stderr)) {Error << "Error in WriteOut( FILE *datei): WriteProtection is turned on.\n"; return -1;}
  if (datei == (FILE*)0) {Error << "Error in WriteOut( FILE *datei): File handler is NULL pointer.\n"; return 1;}
  
  if ( ferror(datei) ) {Error << "Error in WriteOut( FILE *datei): Did not wrote to file, because the file handler indicates an error.\n"; return 1;}
  
  size_t written_buffer = fwrite( c_str(), 1, Len(), datei);
  if (written_buffer != (size_t) Len()) {Error.Printf("Error in WriteOut( FILE *datei): Wrote only %d of %d bytes of the buffer.\n", Len(), written_buffer); return 1;}
  if (fflush(datei)) {Error << "Error in WriteOut( FILE *datei): Could not flush out into file\n"; return 1;}
  
  IsFailed = false;
  return 0;
}

char PrintStringOF::WriteOut( std::fstream *datei)
{
  if (Len()<=0) return 0;
  IsFailed = true;

  if (WriteProtection) {Error << "Error in WriteOut( std::fstream *datei): WriteProtection is turned on.\n"; return -1;}
  if (datei == (std::fstream*)0) {Error << "Error in WriteOut( std::fstream *datei: File handler is NULL pointer.\n"; return 1;}
  
  if ( datei->fail() ) {Error << "Error in WriteOut( std::fstream *datei: Did not wrote to file, because the file handler indicates an error.\n"; return 1;}
  if (! datei->is_open()) {Error << "Error in WriteOut( std::fstream *datei: File is not opened.\n"; return 1;}
  datei->write( c_str(), Len());
  if ( datei->fail() ) {Error << "Error in WriteOut( std::fstream *datei: Failed to write into file.\n"; return 1;}
  
  IsFailed = false;
  return 0;
}








#endif


